

#include <IS61LV25616AL.h>
#include <gd32f10x.h>
#include <rtthread.h>
#include <bsp_usart.h>

void driver_exmc_sram_init(uint32_t norsram_region)
{
    exmc_norsram_parameter_struct nor_init_struct;
    exmc_norsram_timing_parameter_struct nor_timing_init_struct;

    /* EXMC clock enable */
    rcu_periph_clock_enable(RCU_EXMC);

    /* EXMC enable */
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_GPIOD);
    rcu_periph_clock_enable(RCU_GPIOE);
    rcu_periph_clock_enable(RCU_GPIOF);
    rcu_periph_clock_enable(RCU_GPIOG);

    /* configure EXMC_D[0~15]*/
    /* PD14(EXMC_D0), PD15(EXMC_D1),PD0(EXMC_D2), PD1(EXMC_D3), PD8(EXMC_D13), PD9(EXMC_D14), PD10(EXMC_D15) */
    gpio_init(EXMC_D0_3_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_D0_PIN | EXMC_D1_PIN | EXMC_D2_PIN | EXMC_D3_PIN);
    gpio_init(EXMC_D4_12_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_D4_PIN | EXMC_D5_PIN | EXMC_D6_PIN | EXMC_D7_PIN | EXMC_D8_PIN | EXMC_D9_PIN | EXMC_D10_PIN | EXMC_D11_PIN | EXMC_D12_PIN);
    gpio_init(EXMC_D13_15_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_D13_PIN | EXMC_D14_PIN | EXMC_D15_PIN);
    gpio_init(EXMC_A0_9_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_A0_PIN | EXMC_A1_PIN | EXMC_A2_PIN | EXMC_A3_PIN | EXMC_A4_PIN | EXMC_A5_PIN | EXMC_A6_PIN | EXMC_A7_PIN | EXMC_A8_PIN | EXMC_A9_PIN);
    gpio_init(EXMC_A10_15_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_A10_PIN | EXMC_A11_PIN | EXMC_A12_PIN | EXMC_A13_PIN | EXMC_A14_PIN | EXMC_A15_PIN);
    gpio_init(EXMC_A16_18_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_A16_PIN | EXMC_A17_PIN | EXMC_A18_PIN);

    // gpio_init(EXMC_NIORD_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NIORD_PIN);
    // gpio_init(EXMC_NREG_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NREG_PIN);
    // gpio_init(EXMC_NIOWR_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NIOWR_PIN);
    // gpio_init(EXMC_CD_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_CD_PIN);
    // gpio_init(EXMC_INTR_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_INTR_PIN);
    // gpio_init(EXMC_NIOS16_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NIOS16_PIN);
    // gpio_init(EXMC_INT2_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_INT2_PIN);
    // gpio_init(EXMC_INT3_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_INT3_PIN);
    // gpio_init(EXMC_CLK_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_CLK_PIN);
    // gpio_init(EXMC_NWAIT_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NWAIT_PIN);
    // gpio_init(EXMC_NE2_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NE2_PIN);
    // gpio_init(EXMC_NE3_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NE3_PIN);
    // gpio_init(EXMC_NE4_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NE4_PIN);

    gpio_init(EXMC_NOE_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NOE_PIN);
    gpio_init(EXMC_NWE_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NWE_PIN);

    gpio_init(EXMC_NE1_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NE1_PIN);

    gpio_init(EXMC_NBL0_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NBL0_PIN);
    gpio_init(EXMC_NBL1_GROUP, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, EXMC_NBL1_PIN);

    // rt_kprintf("start exmc_norsram_struct_para_init\n");
    exmc_norsram_struct_para_init(&nor_init_struct);
    // rt_kprintf("after exmc_norsram_struct_para_init\n");

    /* config EXMC bus parameters */
    nor_init_struct.norsram_region   = norsram_region;
    nor_init_struct.write_mode       = EXMC_ASYN_WRITE;
    nor_init_struct.extended_mode    = DISABLE;
    nor_init_struct.asyn_wait        = DISABLE;
    nor_init_struct.nwait_signal     = DISABLE;
    nor_init_struct.memory_write     = ENABLE;
    nor_init_struct.nwait_config     = EXMC_NWAIT_CONFIG_BEFORE;
    nor_init_struct.wrap_burst_mode  = DISABLE;
    nor_init_struct.nwait_polarity   = EXMC_NWAIT_POLARITY_LOW;
    nor_init_struct.burst_mode       = DISABLE;
    nor_init_struct.databus_width    = EXMC_NOR_DATABUS_WIDTH_8B;
    nor_init_struct.memory_type      = EXMC_MEMORY_TYPE_SRAM;
    nor_init_struct.address_data_mux = DISABLE;

    /* config timing parameter */
    nor_timing_init_struct.asyn_access_mode       = EXMC_ACCESS_MODE_A;
    nor_timing_init_struct.syn_data_latency       = EXMC_DATALAT_2_CLK;
    nor_timing_init_struct.syn_clk_division       = EXMC_SYN_CLOCK_RATIO_2_CLK;
    nor_timing_init_struct.bus_latency            = 0;
    nor_timing_init_struct.asyn_data_setuptime    = 8;
    nor_timing_init_struct.asyn_address_holdtime  = 8;
    nor_timing_init_struct.asyn_address_setuptime = 8;
    nor_init_struct.write_timing                  = &nor_timing_init_struct;

    nor_init_struct.read_write_timing = &nor_timing_init_struct;

    exmc_norsram_init(&nor_init_struct);

    /* enable the EXMC bank0 NORSRAM */
    exmc_norsram_enable(norsram_region);
}

// extern uint32_t _start_sram, _end_sram;
// static int sram_mem_init(void)
// {
//     uint32_t size = _end_sram - _start_sram;
//     rt_memcpy((uint8_t *)_start_sram, (uint8_t *)EXMC_BANK0_NORSRAM_REGION0_ADDR, size);

//     return 0;
// };

static struct rt_memheap ext_sram_heap; // memheap 控制块
static int8_t ext_sram_init = -1;

int ext_sram_memheap_init(void)
{
    if (ext_sram_init >= 0)
        return 0;
    if (rt_memheap_init(&ext_sram_heap, "ext_sram", (void *)EXMC_BANK0_NORSRAM_REGION0_ADDR, EXMC_SRAM0_SIZE) != RT_EOK) {
        rt_kprintf("error in rt_memheap_init\n");
        ext_sram_init = -1;
    } else {
        rt_kprintf("success in rt_memheap_init\n");
        ext_sram_init = 0;
    }

    return ext_sram_init;
}
MSH_CMD_EXPORT(ext_sram_memheap_init, ext_sram_memheap_init)

int sram_is61lv256_init(void)
{
    rt_kprintf("start driver_exmc_sram_init\n");
    // exmc_norsram_disable(EXMC_BANK0_NORSRAM_REGION0);
    driver_exmc_sram_init(EXMC_BANK0_NORSRAM_REGION0);
    // sram_mem_init();

    rt_kprintf("start ext_sram_memheap_init\n");
    ext_sram_memheap_init();
    return 0;
}

/// @brief write 0x00112233 to sram at BANK0 REGION0 for 20 times,
/// read 32bit value later for 20 times, compare results, if read correctly
/// return 0, else return -1
/// @param
/// @return

// uint8_t ext_sram_mem[1024] SECTION(".extsram");

int sram_is61lv256_rw_test(void)
{
    if (ext_sram_init < 0) {
        sram_is61lv256_init();
    }

    uint32_t sram_value    = 0;
    uint8_t bit32_same_cnt = 0;
    uint8_t bit16_same_cnt = 0;
    uint8_t bit8_same_cnt  = 0;
    char print_buf[50]     = {0};

    uint8_t *ext_sram_mem = rt_memheap_alloc(&ext_sram_heap, 1024);
    if (ext_sram_mem == RT_NULL) {
        rt_kprintf("rt_memheap_alloc failed\n");
        return -1;
    }

    rt_sprintf(print_buf, "ext_sram_mem start: %x\n", (uint32_t)ext_sram_mem);
    rt_kprintf("%s\n", print_buf);

    rt_kprintf("write 32bit value 0x00112233 to sram for 20 times\n");

    __IO uint32_t *u32_p = 0;
    __IO uint16_t *u16_p = 0;
    __IO uint8_t *u8_p   = 0;

    uint8_t pos = 0;
    for (pos = 0; pos < 20; pos++) {
        u32_p  = (__IO uint32_t *)(ext_sram_mem + pos * sizeof(uint32_t));
        *u32_p = 0x00112233;
    }

    rt_kprintf("write finished, start read:\n");

    for (pos = 0; pos < 20; pos++) {
        u32_p      = (__IO uint32_t *)(ext_sram_mem + pos * sizeof(uint32_t));
        sram_value = *u32_p;
        if (sram_value == 0x00112233) {
            bit32_same_cnt++;
        }
    }

    rt_sprintf(print_buf, "write read 32 bit in sram for 20 times, %d passed\n", bit32_same_cnt);
    rt_kprintf("%s\n", print_buf);

    rt_kprintf("write 16bit value 0x0011 to sram for 20 times\n");

    for (pos = 0; pos < 20; pos++) {
        u16_p  = (__IO uint16_t *)(ext_sram_mem + pos * sizeof(uint16_t));
        *u16_p = 0x0011;
    }

    rt_kprintf("write finished, start read:\n");

    for (pos = 0; pos < 20; pos++) {
        u16_p      = (__IO uint16_t *)(ext_sram_mem + pos * sizeof(uint16_t));
        sram_value = *u16_p;
        if (sram_value == 0x0011) {
            bit16_same_cnt++;
        }
    }

    rt_sprintf(print_buf, "write read 16 bit in sram for 20 times, %d passed\n", bit16_same_cnt);
    rt_kprintf("%s\n", print_buf);

    rt_kprintf("write 8bit value 0x12 to sram for 20 times\n");

    for (pos = 0; pos < 20; pos++) {
        u8_p  = (__IO uint8_t *)(ext_sram_mem + pos * sizeof(uint8_t));
        *u8_p = 0x12;
    }

    rt_kprintf("write finished, start read:\n");

    for (pos = 0; pos < 20; pos++) {
        u8_p       = (__IO uint8_t *)(ext_sram_mem + pos * sizeof(uint8_t));
        sram_value = *u8_p;
        if (sram_value == 0x12) {
            bit8_same_cnt++;
        }
    }

    rt_sprintf(print_buf, "write read 8 bit in sram for 20 times, %d passed\n", bit8_same_cnt);
    rt_kprintf("%s\n", print_buf);

    rt_memheap_free(ext_sram_mem);

    return ((bit32_same_cnt == 20) && (bit16_same_cnt == 20) && (bit8_same_cnt == 20));
}

// FINSH_FUNCTION_EXPORT(sram_is61lv256_rw_test, sram read write test);
MSH_CMD_EXPORT(sram_is61lv256_rw_test, sram_read_write_test)